
Imports System.Threading
Imports std

Public Class procEnvHandle
    Public Event environmentChanged(ByVal env As pair(Of String, String))
    Public Event environmentRequired(ByRef envs As map(Of String, String))

    Public Const setenvPrefix As String = "___@$#___PROCENVHANDLE_SETENV___#$@___"
    Public ReadOnly setenvPrefixLen As Int32 = strlen(setenvPrefix)
    Protected Friend _lastInput As String = Nothing
#If RETIRED Then
    Protected Friend _mutex As System.Threading.Mutex
#End If
    Protected Friend _lock As Object = Nothing

#If RETIRED Then
    Public Function mutex() As System.Threading.Mutex
        Return _mutex
    End Function
#End If

    Public Function lock() As Object
        Return _lock
    End Function

    Public Shared ReadOnly searchpathSeparator As String = filesystem.pathSeperator

    Public Class extraEnvName
        Public Const workingpath As String = "workingpath"
        Public Const searchpath As String = "path"
    End Class

    Public Class extraEnvValue
        Public Const workingpath As String = "c:\"
    End Class

    Protected Friend Shared Function containsSysenv(ByVal name As String) As Boolean
#If Not (PocketPC OrElse Smartphone) Then
        Dim collection As System.Collections.IDictionary = System.Environment.GetEnvironmentVariables()
        Dim it As System.Collections.DictionaryEntry = Nothing
        For Each it In collection
            If strsame(Convert.ToString(it.Key), name, False) Then
                Return True
            End If
        Next
#End If

        Return False
    End Function

    Protected Friend Shared Function containsProcenv(ByVal proc As Process, ByVal name As String) As Boolean
#If Not (PocketPC OrElse Smartphone) Then
        Return proc.StartInfo.EnvironmentVariables.ContainsKey(name)
#Else
        Return False
#End If
    End Function

    Public Shared Sub setenvs(ByVal process As Process, ByVal envs As map(Of String, String) _
                                , Optional ByVal overwriteExisting As Boolean = False)
        assert(Not process Is Nothing, "process has not been set.")

        If Not envs Is Nothing Then
#If Not (PocketPC OrElse Smartphone) Then
            Dim work As map(Of String, String).iterator = Nothing
            work = envs.begin()
            While work <> envs.end()
                If overwriteExisting OrElse Not containsProcenv(process, (+work).first) Then
                    process.StartInfo.EnvironmentVariables((+work).first) = (+work).second
                End If
                work += 1
            End While
            process.StartInfo.EnvironmentVariables(extraEnvName.searchpath) += _
                                                   searchpathSeparator + envs(extraEnvName.workingpath)
#End If
            process.StartInfo.WorkingDirectory = envs(extraEnvName.workingpath)
        End If
    End Sub

    Public Shared Sub getenvs(ByVal process As Process, ByRef envs As map(Of String, String))
        assert(Not process Is Nothing, "process has not been set.")

        If envs Is Nothing Then
            envs = New map(Of String, String)
        Else
            envs.clear()
        End If

#If Not (PocketPC OrElse Smartphone) Then
        Dim collection As System.Collections.Specialized.StringDictionary = process.StartInfo.EnvironmentVariables
        Dim it As System.Collections.DictionaryEntry = Nothing
        For Each it In collection
            envs(Convert.ToString(it.Key)) = Convert.ToString(it.Value)
        Next
#End If
        envs(extraEnvName.workingpath) = process.StartInfo.WorkingDirectory()
    End Sub

    Public Sub start()
        '#If Not (PocketPC OrElse Smartphone) Then
        '        assert(Not iohandle Is Nothing, "iohandle has not been set.")
        '#End If
#If RETIRED Then
        _mutex = New System.Threading.Mutex()
#End If
        _lock = New Object()
    End Sub

    Public Sub [stop]()
#If RETIRED Then
        If Not _mutex Is Nothing Then
            _mutex.Close()
        End If
#End If
        _lock = Nothing
    End Sub

    Public Sub envoutputReceive(ByVal s As String, Optional ByVal exited As Boolean = False)
#If RETIRED Then
        assert(_mutex.WaitOne(), "_mutex.WaitOne() returns false.")
#End If
        SyncLock lock()
            _lastInput += s
            If exited Then
                _lastInput += character.newline
            End If
            Dim index As Int32 = 0
            index = _lastInput.IndexOf(character.newline)
            While index <> npos
                Dim line As String = strleft(_lastInput, index)
                kickNewlineChar(line)
                If strsame(line, 0, setenvPrefix, 0, setenvPrefixLen, True) Then
                    Dim temp As vector(Of String) = Nothing
                    Dim env As pair(Of String, String) = Nothing
                    Dim args As String = strmid(line, setenvPrefixLen + 1)
                    kickNewlineChar(args)
                    strsepar(args, character.blank, temp, character.quoteMark, False)
                    If temp.size() = 2 Then
                        env = make_pair(Of String, String)(temp(0), temp(1))
                        RaiseEvent environmentChanged(env)
                    End If
                    '#If Not (PocketPC OrElse Smartphone) Then
                    '            ElseIf strsame(line, 0, getallenvsPrefix, getallenvsPrefixLen, True) Then
                    '                Dim envs As map(Of String, String) = Nothing
                    '                RaiseEvent environmentRequired(envs)
                    '                Dim work As map(Of String, String).node = Nothing
                    '                work = envs.begin()
                    '                While Not work Is Nothing
                    '                    iohandle.input(work.key + character.blank + work.value)
                    '                    work += 1
                    '                End While
                    '#End If
                End If
                _lastInput = strmid(_lastInput, index + 1)
                index = _lastInput.IndexOf(character.newline)
            End While
        End SyncLock
#If RETIRED Then
        _mutex.ReleaseMutex()
#End If
    End Sub

    '#If Not (PocketPC OrElse Smartphone) Then
    '    Private Sub iohandle_errorReceive(ByRef s As String, ByVal exited As Boolean) Handles iohandle.errorReceive
    '        envoutputReceive(s, exited)
    '    End Sub
    '#End If
End Class
